package com.sky.service.impl;

import com.sky.context.BaseContext;
import com.sky.dto.PageQuery;
import com.sky.entity.*;
import com.sky.mapper.BookCaseMapper;
import com.sky.mapper.CategoryMapper;
import com.sky.repository.*;
import com.sky.result.PageResult;
import com.sky.vo.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class BookServiceImpl {
    private static final Logger logger = LoggerFactory.getLogger(BookServiceImpl.class);
    @Autowired
    private BookCaseMapper bookcaseMapper;
    @Autowired
    private BookRepository bookRepository;
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private NoteRepository noteRepository;
    @Autowired
    private ReviewRepository reviewRepository;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private UserActionLogRepository logRepository;

    public List<BookVO> list(Integer tId) {
        return convertToVOList(bookRepository.findBytId(tId));
    }

    public BookVO detail(String id) {
        // 记录操作日志
        UserActionLog log = new UserActionLog();
        log.setAction("read");
        log.setBId(id);
        log.setTimestamp(new Date());
        // 假设通过安全上下文获取当前用户
        log.setUId(BaseContext.getCurrentId());
        logRepository.save(log);
        logger.info("Book detail accessed: {}", id);
        return bookRepository.findById(id)
                .map(this::convertToVO)
                .orElse(null);
    }

    public PageResult search(PageQuery pageQuery) {
        Page<Book> page = bookRepository.searchByKeyword(
                pageQuery.getKw(),
                PageRequest.of(pageQuery.getPage() - 1, pageQuery.getSize())
        );
        return new PageResult(page.getTotalElements(),
                convertToVOList(page.getContent()));
    }

    public List<BookVO> bookcase() {
        Integer uId = BaseContext.getCurrentId();
        List<String> ids = bookcaseMapper.getBookIds(uId);
        return convertToVOList(bookRepository.findByIds(ids));
    }

    public void addToBookCase(String bId) {
        bookcaseMapper.addToBookCase(bId, BaseContext.getCurrentId());
    }

    public void removeFromBookCase(String[] bIds) {
        bookcaseMapper.removeFromBookCase(bIds, BaseContext.getCurrentId());
    }

    public PageResult pageQuery(PageQuery pageQuery) {
        Query query = new Query();
        Criteria criteria = new Criteria();

        String keyword = pageQuery.getKw();
        // 关键字搜索
        if (keyword != null && !keyword.isEmpty()) {
            Criteria keywordCriteria = new Criteria();
            keywordCriteria.orOperator(
                    Criteria.where("title").regex(keyword, "i"),
                    Criteria.where("author").regex(keyword, "i")
            );
            criteria.andOperator(keywordCriteria);
        }
        Integer fId = pageQuery.getFId();
        Integer sId = pageQuery.getSId();
        Integer tId = pageQuery.getTId();
        // 过滤条件
        if (fId != null) {
            criteria.and("fId").is(fId);
        }
        if (sId != null) {
            criteria.and("sId").is(sId);
        }
        if (tId != null) {
            criteria.and("tId").is(tId);
        }

        query.addCriteria(criteria);

        // 查询总数
        long total = mongoTemplate.count(query, Book.class);
        query.with(PageRequest.of(pageQuery.getPage() - 1, pageQuery.getSize()));
        // 查询数据
        List<Book> books = mongoTemplate.find(query, Book.class);

        Map<Integer, String> fCategoryMap = getCategoryMap(books, Book::getFId, categoryMapper::batchFirstDetail);
        Map<Integer, String> sCategoryMap = getCategoryMap(books, Book::getSId, categoryMapper::batchSecondDetail);
        Map<Integer, String> tCategoryMap = getCategoryMap(books, Book::getTId, categoryMapper::batchThirdDetail);

        List<BookVO> bookVOList = books.stream()
                .map(book -> {
                    BookVO vo = new BookVO();
                    BeanUtils.copyProperties(book, vo);
                    vo.setFCategory(fCategoryMap.get(book.getFId()));
                    vo.setSCategory(sCategoryMap.get(book.getSId()));
                    vo.setTCategory(tCategoryMap.get(book.getTId()));
                    return vo;
                })
                .collect(Collectors.toList());

        return new PageResult(total, bookVOList);
    }

    public BookVO detailById(String id) {
        return bookRepository.findById(id)
                .map(book -> {
                    BookVO vo = new BookVO();
                    BeanUtils.copyProperties(book, vo);
                    vo.setFCategory(categoryMapper.firstDetail(book.getFId()).getCategory());
                    vo.setSCategory(categoryMapper.secondDetail(book.getSId()).getCategory());
                    vo.setTCategory(categoryMapper.firstDetail(book.getTId()).getCategory());
                    return vo;
                })
                .orElse(null);
    }

    public List<BookVO> getNoteReview() {
        Integer uId = BaseContext.getCurrentId();
        List<Note> notes = noteRepository.findByuId(uId);
        List<Review> reviews = reviewRepository.findByuId(uId);

        Set<String> bookIds = Stream.concat(
                notes.stream().map(Note::getBId),
                reviews.stream().map(Review::getBId)
        ).collect(Collectors.toSet());

        if (bookIds.isEmpty()) return Collections.emptyList();

        Map<String, Book> bookMap = bookRepository.findByIds(new ArrayList<>(bookIds)).stream()
                .collect(Collectors.toMap(Book::getId, Function.identity()));

        Map<String, Long> noteCountMap = notes.stream()
                .collect(Collectors.groupingBy(Note::getBId, Collectors.counting()));
        Map<String, Long> reviewCountMap = reviews.stream()
                .collect(Collectors.groupingBy(Review::getBId, Collectors.counting()));

        return bookIds.stream()
                .map(bookId -> {
                    BookVO vo = convertToVO(bookMap.get(bookId));
                    vo.setNoteCount(noteCountMap.getOrDefault(bookId, 0L).intValue());
                    vo.setReviewCount(reviewCountMap.getOrDefault(bookId, 0L).intValue());
                    return vo;
                })
                .collect(Collectors.toList());
    }

    public List<NoteVO> getBookNotes(String bId) {
        return convertToNoteVOList(noteRepository.findByuIdAndbId(BaseContext.getCurrentId(), bId));
    }

    public List<ReviewVO> getBookReviews(String bId) {
        return convertToReviewVOList(reviewRepository.findByuIdAndbId(BaseContext.getCurrentId(), bId));
    }

    // Helper methods
    private BookVO convertToVO(Book book) {
        BookVO vo = new BookVO();
        BeanUtils.copyProperties(book, vo);
        return vo;
    }

    private List<BookVO> convertToVOList(List<Book> books) {
        return books.stream().map(this::convertToVO).collect(Collectors.toList());
    }

    private List<NoteVO> convertToNoteVOList(List<Note> notes) {
        return notes.stream().map(note -> {
            NoteVO vo = new NoteVO();
            BeanUtils.copyProperties(note, vo);
            return vo;
        }).collect(Collectors.toList());
    }

    private List<ReviewVO> convertToReviewVOList(List<Review> reviews) {
        return reviews.stream().map(review -> {
            ReviewVO vo = new ReviewVO();
            BeanUtils.copyProperties(review, vo);
            return vo;
        }).collect(Collectors.toList());
    }

    private Map<Integer, String> getCategoryMap(List<Book> books,
                                                Function<Book, Integer> idExtractor,
                                                Function<Set<Integer>, List<Category>> categoryFetcher) {
        Set<Integer> ids = books.stream().map(idExtractor).collect(Collectors.toSet());
        return categoryFetcher.apply(ids).stream()
                .collect(Collectors.toMap(Category::getId, Category::getCategory));
    }
}